package com.tangyh.basic.utils.network;

import com.alibaba.fastjson.JSONObject;
import com.tangyh.basic.base.AR;
import com.tangyh.basic.base.constant.StringPool;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;

import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * OKHttp请求工具类
 *
 * @version V1.0
 * @author: Sidon
 * @createTime: 2021-06-03 16:41
 * Copyright (C)2021-2021 福建省金柠网络科技有限公司. All rights reserved.
 */
@Slf4j
public class OkHttpUtils {


    private static final int SUCCESS_CODE = 200;

    private static final int CONNECT_TIMEOUT = 20;
    private static final int READ_TIMEOUT = 60;
    private static final int WRITE_TIMEOUT = 60;
    private static final X509TrustManager MANAGER = SSLSocketClientUtil.getX509TrustManager();
    private static final OkHttpClient OK_HTTP_CLIENT = new OkHttpClient.Builder()
            .protocols(Collections.singletonList(Protocol.HTTP_1_1))
            .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
            .readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
            .writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS)
            .sslSocketFactory(SSLSocketClientUtil.getSocketFactory(MANAGER), MANAGER)
            .hostnameVerifier(SSLSocketClientUtil.getHostnameVerifier())
            .build();

    /**
     * Get请求
     * 响应主体大于1 MB,建议使用流处理，不要直接以字符操作
     *
     * @param url 请求地址
     * @return 响应结果
     */
    @NonNull
    public static AR<String> httpGet(String url) {
        AR<String> checkResult = checkUrl(url);
        if (checkResult.isFail()) {
            return checkResult;
        }
        return httpGet(url, Collections.emptyMap());
    }

    /**
     * Get请求携带请求头
     * 响应主体大于1 MB,建议使用流处理
     *
     * @param url   请求地址
     * @param param 请求参数
     * @return 响应结果
     */
    @NonNull
    public static AR<String> httpGet(String url, Map<String, Object> param) {
        return httpGet(url, param, Collections.emptyMap());
    }

    /**
     * Get请求携带请求头
     * 响应主体大于1 MB,建议使用流处理
     *
     * @param url     请求地址
     * @param headers 请求头
     * @param param   请求参数
     * @return 响应结果
     */
    @NonNull
    public static AR<String> httpGet(String url, Map<String, Object> param, Map<String, String> headers) {
        AR<String> checkResult = checkUrl(url);
        if (checkResult.isFail()) {
            return checkResult;
        }

        HttpUrl.Builder httpBuilder = HttpUrl.parse(url).newBuilder();
        if (!param.isEmpty()) {
            param.forEach((key, value) -> httpBuilder.addQueryParameter(key, String.valueOf(value)));
        }
        Request.Builder builder = new Request.Builder();
        if (!headers.isEmpty()) {
            headers.forEach(builder::header);
        }
        Request request = builder.get().url(httpBuilder.build()).build();
        return prepareResult(request, param.toString());
    }

    /**
     * Post请求，无携带请求头，参数为JSON格式
     *
     * @param url 请求地址
     * @param map 请求参数，map格式
     * @return 响应结果
     */
    @NonNull
    public static AR<String> httpPost(String url, Map<String, Object> map) {
        return httpPost(url, Collections.emptyMap(), map);
    }

    /**
     * Post请求，携带请求头，参数为JSON格式
     *
     * @param url     请求地址
     * @param map     请求参数，map格式
     * @param headers 请求头
     * @return 响应结果
     */
    @NonNull
    public static AR<String> httpPost(String url, Map<String, String> headers, Map<String, Object> map) {
        AR<String> checkResult = checkUrl(url);
        if (checkResult.isFail()) {
            return checkResult;
        }
        //Post请求参数
        FormBody.Builder builder = new FormBody.Builder();
        map.forEach((key, value) -> builder.add(key, String.valueOf(value)));
        Request.Builder requestBuild = new Request.Builder().url(url);
        if (!headers.isEmpty()) {
            headers.forEach(requestBuild::addHeader);
        }

        Request request = requestBuild
                .post(builder.build())
                .build();

        return prepareResult(request, map.toString());
    }

    /**
     * Post请求，无携带请求头，参数为JSON格式
     *
     * @param url  请求地址
     * @param json 请求参数，JSON格式
     * @return 响应结果
     */
    @NonNull
    public static AR<String> httpPost(String url, String json) {
        return httpPost(url, Collections.emptyMap(), json);
    }

    /**
     * Post请求，携带请求头，参数为JSON格式
     *
     * @param url     请求地址
     * @param json    请求参数，JSON格式
     * @param headers 请求头
     * @return 响应结果
     */
    @NonNull
    public static AR<String> httpPost(String url, Map<String, String> headers, String json) {
        AR<String> checkResult = checkUrl(url);
        if (checkResult.isFail()) {
            return checkResult;
        }

        MediaType mediaType = MediaType.parse(StringPool.HTTP_JSON);
        RequestBody body = RequestBody.create(mediaType, json);
        Request.Builder requestBuilder = new Request.Builder().url(url);
        if (!headers.isEmpty()) {
            headers.forEach(requestBuilder::addHeader);
        }
        Request request = requestBuilder.post(body).build();
        return prepareResult(request, json);
    }

    /**
     * 参数以表单格式提交，并携带请求头
     * 表单格式为：application/x-www-form-urlencoded; charset=utf-8，
     * 参数格式为：param1=1&param2=2
     *
     * @param url     请求地址
     * @param content 请求内容，application/x-www-form-urlencoded格式
     * @param headers 请求头
     * @return 响应结果
     */
    @NonNull
    public static AR<String> postDataByForm(String url, Map<String, String> headers, String content) {
        AR<String> checkResult = checkUrl(url);
        if (checkResult.isFail()) {
            return checkResult;
        }

        MediaType mediaType = MediaType.parse(StringPool.HTTP_FORM);
        RequestBody body = RequestBody.create(mediaType, content);
        Request.Builder requestBuilder = new Request.Builder().url(url);
        if (!headers.isEmpty()) {
            headers.forEach(requestBuilder::addHeader);
        }
        Request request = requestBuilder.post(body).build();
        return prepareResult(request, content);
    }


    /**
     * 处理请求结果
     *
     * @param request OKHttp请求对象
     * @return 处理结果
     */
    @NonNull
    private static AR<String> prepareResult(Request request) {
        return prepareResult(request, StringPool.EMPTY);
    }

    /**
     * 处理请求结果
     *
     * @param request OKHttp请求对象
     * @param param   请求参数
     * @return 处理结果
     */
    @NonNull
    private static AR<String> prepareResult(Request request, String param) {
        try {
            Response response = OK_HTTP_CLIENT.newCall(request).execute();
            if (response.code() == SUCCESS_CODE) {
                log.info("{} 请求成功; [url={}, param={}]", request.method(), request.url().url(), param.length() > 100 ? "请求参数过长" : param);
                System.out.printf("%s 请求成功; [url=%s, param=%s]%n", request.method(), request.url().url(), param.length() > 100 ? "请求参数过长" : param);
                if (response.body() != null) {
                    return AR.success(response.body().string(), response.message(), String.valueOf(response.code()));
                }
                return AR.success(null, "请求成功，返回结果为空", String.valueOf(response.code()));
            } else {
                log.warn("{} 请求失败; [ErrorCode = {} , url={}, param={}]", request.method(), response.code(), request.url().url(), param.length() > 100 ? "请求参数过长" : param);
                System.out.printf("%s 请求失败; [ErrorCode = %s , url=%s, param=%s]%n", request.method(), response.code(), request.url().url(), param.length() > 100 ? "请求参数过长" : param);
                if (response.body() != null) {
                    return AR.fail(String.valueOf(response.code()), "请求失败", response.body().string());
                }
                return AR.fail(String.valueOf(response.code()), "请求成功，返回结果为空", response.message());
            }
        } catch (IOException e) {
            return AR.error(e, String.format("Http Post Form请求失败,url: %s", request.url().url()));
        }
    }

    /**
     * 验证请求地址是否合法
     *
     * @param url 请求地址
     * @return 验证结果
     */
    private static AR<String> checkUrl(String url) {
        if (url == null || url.isEmpty()) {
            log.error("请求地址为空或!");
            return AR.fail("请求地址为空!");
        }
        if (!url.startsWith(StringPool.HTTP) && !url.startsWith(StringPool.HTTPS)) {
            log.error("URL的Scheme必须为Http或Https");
            return AR.fail("请求地址为的Scheme必须包含Http或Https!");
        }
        return AR.success(StringPool.EMPTY);
    }

    public static void main(String[] args) {
//        String url = "https://www.baidu.com";
//        AR<String> stringAR = httpGet(url);
//        System.out.println(stringAR.getCode() + "::" + stringAR.isSuccess() + "::" + stringAR.isFail() + "::" + stringAR.getReturnCode() + "::" + stringAR.getMsg());
//        System.out.println(stringAR);

        JSONObject obj = new JSONObject();
        obj.put("accountId", "CAnwFbOUCbwICfAVs5QJvC7J6gpVrdRPJWu1kTFXf5wnb5ceSl9OE5UK08x6fxT6Ntrt883m6AA");
        String url = "https://etest2.spdb.com.cn/spdb/uat/api/partner/account/queryAccount";

        Map<String, String> header = new HashMap<>();
        header.put("X-SPDB-Client-Id", "d83fa07c-0b7f-40e5-b53a-8c21f3c0437f");
        header.put("X-SPDB-SIGNATURE", "nS6uP3oO5wK4dY8uX4aN0tT7hH6rU8jU7oW6aE7aI6iV6qO4qD");


        AR<String> stringAR = httpPost(url, header, obj.toString());
        //String jsonSTR="{\"accountId\": \"CAnwFbOUCbwICfAVs5QJvGsibK6O0tRQq4fAKmf8SiblQnb5ceSl9OE1mibtn09U3FONtrt883m6AA\"}";
        System.out.println(obj.toString());
        System.out.println(stringAR.getErrorMessage());
    }
}
